/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package horsechess.server.data;

import horsechess.packet.MatchPacket;
import horsechess.packet.PlayerPacket;
import horsechess.server.gui.GUIServer;
import horsechess.util.Status;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import javax.swing.Timer;

/**
 *
 * @author Administrator
 */
public class ClientHandler implements Runnable, ActionListener {

    public PrintWriter out;
    private BufferedReader reader;
    public Socket socket;
    public PlayerPacket player;
    public String receiveMessage;
    private RoomManager room;
    private GUIServer uIServer;
    public Status status;
    private PlayerPacket otherPlayer;
    private javax.swing.Timer m_t;

    public ClientHandler(Socket clientSocket, GUIServer server) {
        try {
            this.socket = clientSocket;
            // clientSocket.setSoTimeout(timeout);
            InputStreamReader isReader = new InputStreamReader(socket.getInputStream());
            out = new PrintWriter(socket.getOutputStream(), true);
            reader = new BufferedReader(isReader);
            this.uIServer = server;
            m_t = new Timer(10000, this);
            m_t.start();
        } catch (Exception e) {
            ServerHandler.status = Status.EXCEPTION;
            GUIServer.txtServerStatus.setText("There are error when Server establish connection with client: " + e.getMessage());
        }
    }

    public void send(String message) {
        //System.out.println("Sending message: " + message);
        out.println(message);
    }

    public String getName() {
        return player.getPlayerName();
    }

    public void setRoom(RoomManager room) {
        this.room = room;
    }

    public RoomManager getRoom() {
        return room;
    }

    /**
     * Receive message from clients
     */
    public void run() {
        Scanner scanner = new Scanner(System.in);
        try {
            while ((receiveMessage = reader.readLine()) != null) {
                processMessage();
                Thread.sleep(100);
            }
        } catch (SocketException se) {
            handleDisconnect();
        } catch (Exception e) {
            ServerHandler.status = Status.EXCEPTION;
            e.printStackTrace();
            GUIServer.txtServerStatus.setText("Error occured when receiving messages: " + e.getMessage());
        }

    }

    private void handleDisconnect() {
        try {
            ServerHandler.status = Status.EXCEPTION;
            //se.printStackTrace();
            room.broadcastMesage("@Chat#" + player.getPlayerName() + ": have been out of game.");
            room.broadcastMessage(player.toString() + "#" + Status.DISCONNECTED.toString(), player.getPlayerName());
            room.removeClient(this);
            socket.close();
            if (room.clients.size() == 1 && room.clients.get(0).status == Status.PLAYING) {
                ClientHandler client = room.clients.get(0);
                client.send(client.player.toString() + "#" + Status.SHUT_DOWN.toString());
                client.socket.close();
                room.removeClient(client);
            } else {
                status = Status.CONNECTED;
                handleStatus();
            }
            GUIServer.txtServerStatus.setText(player.getPlayerName() + " have been disconnect with server !!!!");
            uIServer.displayRoomInfo();
        } catch (IOException ex) {
            ServerHandler.status = Status.EXCEPTION;
            GUIServer.txtServerStatus.setText("Client has failed to close connect : " + ex.getMessage());
        }
    }

    private void processMessage() {

        //System.out.println("read " + receiveMessage);
        handleRoom();
        handleDice();
        handleChat();
        handlePosition();
        handleDisconnectPlayer();
        handleClock();
         handleTurnOfPlayer();
         handleLose();
         handleWon();
         handleGameOver();
    }

    public void handleClock(){
        String[] msgs = receiveMessage.split("#");
        if(msgs[0].equalsIgnoreCase("@Clock"))
        {
            if(msgs[1].equalsIgnoreCase("Stop")) room.stop();
            if(msgs[1].equalsIgnoreCase("Restart")) room.restart();
        }
    }

    public void handleGameOver(){
        
        if(receiveMessage.equalsIgnoreCase("@GAME_OVER"))
        {
            room.broadcastMesage(receiveMessage);
        }
    }
    public void handleLose(){
        String[] msgs = receiveMessage.split("#");
        if(msgs[0].equalsIgnoreCase("@Lose"))
        {
            ClientHandler loseClient=room.getClient(msgs[1].trim());
            loseClient.send(receiveMessage);
        }
    }
    public void handleWon(){
         String[] msgs = receiveMessage.split("#");
        if(msgs[0].equalsIgnoreCase("@Won"))
        {
            ClientHandler wonClient=room.getClient(msgs[1].trim());
            wonClient.send(receiveMessage);
        }
    }

    public void handlePosition()
    {
         String[] msgs = receiveMessage.split("#");
        if (msgs[0].equalsIgnoreCase("@HorseMove")){
            room.broadcastMesage(receiveMessage);
        }
    }

    public void handleDice() {
        String[] msgs = receiveMessage.split("#");
        if (msgs[0].equalsIgnoreCase("@RollDice")) {
            String messageSend = "@RollDice#";
            int value = Integer.parseInt(msgs[1]);
            Random rd = new Random();
            int diceValue = 0;
            if (value == 1) {
                diceValue = rd.nextInt(6) + 1;
                messageSend += diceValue+"#"+0;
            } else {
                diceValue = rd.nextInt(6) + 1;
                messageSend += diceValue;
                diceValue = rd.nextInt(6) + 1;
                messageSend +="#"+ diceValue;
            }


            room.broadcastMesage(messageSend);
        }
    }

    public void handleChat() {
        String[] msgs = receiveMessage.split("#");
        if (msgs[0].equals("@Chat")) {
            room.broadcastMesage(receiveMessage);
        }
    }

    public void handleStatus() {
        switch (status) {
            case WON:
                ClientHandler wonClient = room.getClient(otherPlayer.getPlayerName());
                wonClient.send(Status.toString(Status.WON));
                wonClient.send(otherPlayer.toString());
                room.broadcastMessage(Status.toString(Status.LOSE), wonClient.getName());
                ArrayList losers = room.getLoser(wonClient.getName());
                for (int i = 0; i < losers.size(); i++) {
                    ClientHandler loser = (ClientHandler) losers.get(i);
                    MatchPacket packet = new MatchPacket(wonClient.getName(), loser.getName());
                    loser.send(packet.toString());
                }
                break;
            case CONNECTED:
                room.broadcastMesage(Status.toString(Status.CONNECTED));

                room.broadcastMesage("@NoOfPlayer#" + room.clients.size());
                room.broadcastInfoAllPlayerInRoom();
                break;
        }
    }

    public void actionPerformed(ActionEvent e) {
        //handleStatus();
    }

    

   

    private void handleRoom() {
        // Finished join room then change status of server to connected
        String[] msgs = receiveMessage.split("-");
        if (msgs[0].equals("@Room")) {
            List<RoomManager> rooms = Server.listOfRoom();
            player = new PlayerPacket(msgs[2], msgs[1]);
            for (int i = 0; i < rooms.size(); i++) {
                RoomManager roomManager = rooms.get(i);
                roomManager.removeClient(this);
                if (roomManager.getRoomName().equalsIgnoreCase(msgs[1])) {
                    //    if (!roomManager.clients.contains(this)) {
                    roomManager.registerClient(this);
                    this.setRoom(roomManager);
                    player.setPosOfPlayer(roomManager.clients.indexOf(this));
                    //  }

                }
            }
            status = Status.CONNECTED;
            handleStatus();

        }
    }
    public void kickPlayer(){
          String[] msgs = receiveMessage.split("#");
        if(msgs[0].equalsIgnoreCase("@Disconnected"))
        {
            room.broadcastMesage(receiveMessage);
        }
    }

    private void handleDisconnectPlayer() {
        String[] msgs = receiveMessage.split("#");
        if (msgs[0].equals("@Status") && msgs[1].equals(Status.DISCONNECTED.toString())) {
            try {
                ServerHandler.status = Status.EXCEPTION;
                room.broadcastMesage("@Chat#" + player.getPlayerName() + ": have been out of game.");
                room.broadcastMessage(player.toString() + "#" + Status.DISCONNECTED.toString(), player.getPlayerName());
                room.removeClient(this);
                socket.close();
                if (room.clients.size() == 1 && room.clients.get(0).status == Status.PLAYING) {
                    ClientHandler client = room.clients.get(0);
                    client.send(client.player.toString() + "#" + Status.SHUT_DOWN.toString());
                    client.socket.close();
                    room.removeClient(client);
                } else {
                    status = Status.CONNECTED;
                    handleStatus();
                }
                GUIServer.txtServerStatus.setText(player.getPlayerName() + " have been disconnect with server !!!!");
                uIServer.displayRoomInfo();
            } catch (IOException ex) {
                ServerHandler.status = Status.EXCEPTION;
                GUIServer.txtServerStatus.setText("Client has failed to close connect : " + ex.getMessage());
            }
        }
    }

    private void handleTurnOfPlayer(){
         String[] msgs = receiveMessage.split("#");
         if (msgs[0].equals("@Turn")) {
            room.broadcastMessage(receiveMessage, this.getName());
        }
    }
}
